﻿using System;
using CookComputing.XmlRpc;
using EPiAbstractions.Community;
using EPiAbstractions.Community.Blog.Security;
using EPiServer.Common.Security;
using EPiServer.Community.Blog;
using EPiServer.Community.Blog.Security;
using JoelAbrahamsson.TestUtilities;
using Moq;
using StructureMap.AutoMocking;
using Xunit;

namespace JoelAbrahamsson.MetaWeblog.Tests
{
    public class ValidateUserTests : IUseFixture<BlogModuleFixture>
    {
        public void SetFixture(BlogModuleFixture data) {}

        [Fact]
        public void GivenInvalidCredentials_ValidateUser_ThrowsException()
        {
            string username = RandomValues.String;
            string password = RandomValues.String;
            Blog blog = new Blog(RandomValues.String);
            Mock<IDefaultSecurityHandlerFacade> fakeSecurityHandler = CreateFakeSecurityHandler(username, password, false);
            Mock<ISecurityHandlerFacade> fakeBlogSecurityHandlerFacade = CreateFakeBlogSecurityHandlerFacade(SufficientAccessRights);
            MetaWeblogHandler metaWeblogHandler = CreateMetaWeblogHandler(fakeSecurityHandler.Object, fakeBlogSecurityHandlerFacade.Object);

            Exception exception = Record.Exception(
                () => metaWeblogHandler.GetValidatedUser(blog, username, password));

            Assert.NotNull(exception);
            Assert.Equal<Type>(typeof(XmlRpcFaultException), exception.GetType());
        }

        private MetaWeblogHandler CreateMetaWeblogHandler(IDefaultSecurityHandlerFacade securityHandler, ISecurityHandlerFacade blogSecurityHandlerFacade)
        {
            MoqAutoMocker<MetaWeblogHandler> metaWebLogHandlerAutoMocker = new MoqAutoMocker<MetaWeblogHandler>();
            metaWebLogHandlerAutoMocker.Inject(securityHandler);
            metaWebLogHandlerAutoMocker.Inject(blogSecurityHandlerFacade);
            return metaWebLogHandlerAutoMocker.ClassUnderTest;
        }

        [Fact]
        public void GivenInsufficientAccessRights_ValidateUser_ReturnsFalse()
        {
            string username = RandomValues.String;
            string password = RandomValues.String;
            Mock<IDefaultSecurityHandlerFacade> fakeSecurityHandler = CreateFakeSecurityHandler(username, password, true);
            Blog blog = CreateBlog();
            BlogAccessRights accessRights = new BlogAccessRights();
            Mock<ISecurityHandlerFacade> fakeBlogSecurityHandlerFacade = CreateFakeBlogSecurityHandlerFacade(accessRights);
            MetaWeblogHandler metaWeblogHandler = CreateMetaWeblogHandler(fakeSecurityHandler.Object, fakeBlogSecurityHandlerFacade.Object);

            Exception exception = Record.Exception(
                () => metaWeblogHandler.GetValidatedUser(blog, username, password));

            Assert.NotNull(exception);
            Assert.Equal<Type>(typeof(XmlRpcFaultException), exception.GetType());
        }

        [Fact]
        public void GivenValidCredentialsAndSufficientAccessRights_ValidateUser_ReturnsTrue()
        {
            string username = RandomValues.String;
            string password = RandomValues.String;
            Blog blog = new Blog(RandomValues.String);
            Mock<IDefaultSecurityHandlerFacade> fakeSecurityHandler = CreateFakeSecurityHandler(username, password, true);
            Mock<ISecurityHandlerFacade> fakeBlogSecurityHandlerFacade = CreateFakeBlogSecurityHandlerFacade(SufficientAccessRights);
            MoqAutoMocker<MetaWeblogHandler> metaWebLogHandlerAutoMocker = new MoqAutoMocker<MetaWeblogHandler>();
            metaWebLogHandlerAutoMocker.Inject(fakeSecurityHandler.Object);
            metaWebLogHandlerAutoMocker.Inject(fakeBlogSecurityHandlerFacade.Object);

            Exception exception = Record.Exception(
                () => metaWebLogHandlerAutoMocker.ClassUnderTest.GetValidatedUser(blog, username, password));

            Assert.Null(exception);
        }

        private BlogAccessRights SufficientAccessRights
        {
            get
            {
                return new BlogAccessRights { CreateEntry = true, UpdateEntry = true };
            }
        }

        private Mock<IDefaultSecurityHandlerFacade> CreateFakeSecurityHandler(string username, string password, bool userValidationShouldSucceed)
        {
            var fakeSecurityHandler = new Mock<IDefaultSecurityHandlerFacade>();
            IUser user = null;
            if (userValidationShouldSucceed)
                user = new Mock<IUser>().Object;
            fakeSecurityHandler.Setup(handler => handler.AuthenticateUser(username, password, out user)).Returns(userValidationShouldSucceed);
            return fakeSecurityHandler;
        }

        private Blog CreateBlog()
        {
            return new Blog(RandomValues.String);
        }

        private Mock<ISecurityHandlerFacade> CreateFakeBlogSecurityHandlerFacade(BlogAccessRights accessRights)
        {
            var fakeBlogSecurityHandlerFacade = new Mock<ISecurityHandlerFacade>();
            fakeBlogSecurityHandlerFacade.Setup(facade => facade.GetTotalBlogAccessRights(It.IsAny<Blog>(), It.IsAny<IUser>())).Returns(accessRights);
            return fakeBlogSecurityHandlerFacade;
        }
    }
}
